Q = @

# 假想目标总是尚未更新，总是会被执行，并会使得他们的依存对象被重建
# 变量名称是单一字符则不需要括号
.PHONY: versions
versions:
	$Qecho "hahaha"
	$Qtouch versions

.PHONY: /aaa/bbb.c /ccc/ddd.c /xxx auto_var
/aaa/bbb.c:
/xxx:

# 自动变量可在之后加上"D"后者"F"
/ccc/ddd.c: /aaa/bbb.c /xxx
	$(Q)echo "$@"     # /ccc/ddd.c
	$(Q)echo "$<"     # /aaa/bbb.c
	$(Q)echo "$?"     # /aaa/bbb.c /xxx
	$(Q)echo "$^"     # /aaa/bbb.c /xxx
	$(Q)echo "$+"     # /aaa/bbb.c /xxx
	$(Q)echo "$*"     # /ccc/ddd
	$(Q)echo "$(@D)"  # /ccc
	$(Q)echo "$(<D)"  # /aaa
	$(Q)echo "$(@F)"  # /ddd.c
	$(Q)echo "$(<F)"  # /bbb.c

auto_var: /ccc/ddd.c

# VPATH 或 vpath 指定源文件查找目录
# vpath %.c src
# vpath %.h include

# 静态模式规则，指定规则只应用在特定变量上
$(objs): %.o: %.c
	gcc -c $< -o $@

AWK = awk
SORT = sort
PR = pr
.PHONY: help
help:
	$(Q)$(MAKE) --print-data-base --question | \
	$(AWK) '/^[^.%][-A-Za-z0-9_]*:/{print substr($$1,1,length($$1)-1)}' | \
	$(SORT) | \
	$(PR) --omit-pagination --width=80 --columns=4

# 自动生成依赖
# $$ 在shell中为当前进程号
CC = gcc
.PHONY: dep
dep: stdio.o libb.a
-include stdio.d
%.d: %.c
	@set -e; rm -f $@; \
	$(CC) -M $(CPPFLAGS) $< > $@.$$$$; \
	sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \
	rm -f $@.$$$$

# 特定程序库中特定成员，程序库作为必要条件，可用-l语法引用
AR = ar
libb.a: libb.a(stdio.o)
libb.a(stdio.o): stdio.o -lpthread
	$(Q)$(AR) -rv $@ $?
	$(Q)echo $^
